/*
 * Università degli Studi di Trento
 * Facoltà di Scienze MM.FF.NN.
 * Corso di Laurea Triennale in Informatica
 * A.A. 2010/2011
 * Progetto per il corso di Sistemi Operativi 1
 * Progetto 4: simulazione di una rotonda
 * Autori:
 *  Abram Lorenzo - 140368
 *  Dal Lago Loris - 139428
 *  Florio Alessandro - 140245
 */

/********************************************************************************
  Semplice implementazione di una coda specializzata per il tipo ptrCar

  Operazioni di enqueue e dequeue saranno chiamate solo dalla rotatoria che si
  occupera' di gestire con dei mutex gli accessi concorrenti
********************************************************************************/

#include "queue.h"

typedef struct SNode * ptrNode;

typedef struct SNode {
  ptrCar car;
  ptrNode next;
} Node;

typedef struct SQueue {  
  ptrNode head;
  ptrNode tail;
} Queue;

static void Queue_init(ptrQueue queue){
  queue->head = queue->tail = NULL;
}

ptrQueue Queue_create(){
  ptrQueue queue = new(Queue);
  Queue_init(queue);
  return queue;
}

static bool Queue_is_empty (const ptrQueue queue) 
{
  return (queue->head == NULL);
}

void Queue_enqueue(ptrCar car, ptrQueue queue)
{
  ptrNode node = new(Node);
  node->car = car;
  node->next = NULL;
  if (Queue_is_empty(queue)) 
    queue->head = queue->tail = node;
  else {
    queue->tail->next = node;
    queue->tail = node;
  }
#ifdef DEBUG
  Queue_printf(queue);
#endif

}

ptrCar Queue_top(ptrQueue queue)
{
  if (Queue_is_empty(queue))
    return (ptrCar)NULL;
  else {
	  return queue->head->car;
  }
}

void Queue_dequeue(ptrQueue queue)
{ 
  ptrNode first;
  if (Queue_is_empty(queue)) {
    throw_error("Queue_dequeue", "la coda e' vuota!");
  } else {
    first = queue->head;   
    queue->head = first->next;
    delete(first); 
   
  }
}

#ifdef DEBUG

void Queue_printf (ptrQueue queue){
  if (!Queue_is_empty(queue)) {
    ptrNode first = queue->head;
    do {
    	printf("\tqueue: ");
      Car_printf(first->car);
      first = first->next;
    } while (first != NULL);
  }
}

#endif /* DEBUG */

static void Queue_deinit(ptrQueue queue){
  while (!Queue_is_empty(queue)){
    ptrNode first = queue->head;    
    queue->head = queue->head->next;
    delete(first->car);
    delete(first); 
  }
};

/* Note: when a queue is destroyed, also the cars it holds are.  */
void Queue_destroy(ptrQueue queue){
  if (queue != NULL){
    Queue_deinit(queue);
    delete(queue);
  }
}
